package amit.ui.table;

import javax.swing.*;
import javax.swing.table.*;

import sun.nio.cs.ext.ISCII91;

import java.awt.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * General table utils like: Setting column width, show specific cell etc'
 * 
 * @author ido
 * 
 */
public class TableUtils {

	/**
	 * save the last point on the table search
	 */
	private static Point lastPoint = new Point(0,0);
	private static String lastSearchText = "";
	
	private static int MAX_LENGTH_OF_COLUMN = 200;
	/**
	 * Calculate the required width of a table column
	 */
	public static int calculateColumnWidth(JTable table, int columnIndex) {
		int width = 50; // The return value
		int rowCount = table.getRowCount();

		for (int i = 0; i < rowCount; i++) {
			TableCellRenderer renderer = table.getCellRenderer(i, columnIndex);
			Component comp = renderer.getTableCellRendererComponent(table,
					table.getValueAt(i, columnIndex), false, false, i,
					columnIndex);
			int thisWidth = Math.min(MAX_LENGTH_OF_COLUMN, comp.getPreferredSize().width);
			if (thisWidth > width) {
				width = thisWidth;
			}
		}
		return width;
	}

	/**
	 * Set the widths of every column in a table
	 */
	public static void setColumnWidths(JTable table, Insets insets,
			boolean setMinimum, boolean setMaximum) {
		int columnCount = table.getColumnCount();
		TableColumnModel tcm = table.getColumnModel();
		int spare = (insets == null ? 0 : insets.left + insets.right);

		for (int i = 0; i < columnCount; i++) {
			int width = calculateColumnWidth(table, i);
			width += spare;

			TableColumn column = tcm.getColumn(i);
			column.setPreferredWidth(width);
			if (setMinimum == true) {
				column.setMinWidth(width);
			}
			if (setMaximum == true) {
				column.setMaxWidth(width);
			}
		}
	}

	/**
	 * Ensure that the cell (x,y) is visible example: int rowIndex = 1; int
	 * vColIndex = 2; scrollToVisible(table, rowIndex, vColIndex);
	 * 
	 * @param table
	 * @param rowIndex
	 * @param vColIndex
	 */
	public static void makeCellVisiable(JTable table, int rowIndex,
			int vColIndex) {
		if (!(table.getParent() instanceof JViewport)) {
			return;
		}
		JViewport viewport = (JViewport) table.getParent();

		// This rectangle is relative to the table where the
		// northwest corner of cell (0,0) is always (0,0).
		Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);

		// The location of the viewport relative to the table
		Point pt = viewport.getViewPosition();

		// Translate the cell location so that it is relative
		// to the view, assuming the northwest corner of the
		// view is (0,0)
		rect.setLocation(rect.x - pt.x, rect.y - pt.y);

		// Scroll the area into view
		viewport.scrollRectToVisible(rect);
		table.setRowSelectionInterval(rowIndex, rowIndex);
		table.setColumnSelectionInterval(vColIndex, vColIndex);

	}

	/**
	 * make sure we don't change non editable cells
	 * 
	 * @param table
	 * @param i
	 * @param j
	 * @return In case this cell is not editable return false
	 */
	private static boolean isCellEditable(JTable table, int i, int j) {
//		if (table instanceof AdTable) {
//			return ((AdTable)table).getTableFormat().isEditable(null, j);
//		}
//		else {
			return table.getModel().isCellEditable(i, j);
	}
	
	/**
	 * 
	 * @param table
	 * @param text
	 * @param options
	 * @param newText - if the user click on 'replace' this var. will contain string
	 * @return true - when the string was found in the table
	 * 
	 * No options = 0; CASE_SENSITIVE = 1; WHOLE_WORD = 10;
	 */
	public static boolean findReplaceStringInTable(JTable table, String text,
			int options, String newText) {
		TableModel tml = table.getModel();
		int maxRow = tml.getRowCount();
		int maxCol = table.getColumnModel().getColumnCount(); 
				
		if ( !lastSearchText.equalsIgnoreCase(text)) {
			lastPoint.setLocation(0, 0);
		}
		lastSearchText = text;
		int j = (int)lastPoint.getY()+1;
		for (int i = (int)lastPoint.getX(); i < maxRow; i++) {
			while (j < maxCol) {
				String tmp = "";
				int modelJ = table.getColumnModel().getColumn(j).getModelIndex();
				if (tml.getValueAt(i, modelJ) != null) {
					tmp = (tml.getValueAt(i, modelJ)).toString();
				}
				//System.out.println("@@tmp: " +tmp + " j="+j+ " lastPoint:"+lastPoint +" now: ("+i+","+modelJ+") options:" + options);
				switch (options) {
				case 0:
					// no options
					String patternStr = text;
		            Pattern pattern = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);	    
		            Matcher matcher = pattern.matcher(tmp);
		            //System.out.println("tmp: "+tmp + " pattern:"+pattern + " newText:"+newText); 
		            if (matcher.find()) {
		            	lastPoint.setLocation(i, j);
		            	if (newText == null) {
			            	makeCellVisiable(table, i, j);   //	System.out.println("%%% match point:"+i+","+j);
			            	return true;
		            	}
		            	// if we have replace operation
		            	if (isCellEditable(table, i,modelJ)) {
		            		tmp = tmp.replaceAll(text, newText);    		
		            		tml.setValueAt(tmp, i, modelJ);
			            	makeCellVisiable(table, i, j);   //	System.out.println("%%% match point:"+i+","+j);
			            	return true;
						}
		            }
					break;
				case 1:
					// CASE_SENSITIVE
					if (tmp.indexOf(text) > -1) {
						lastPoint.setLocation(i, j);
		            	if (newText == null) {
			            	makeCellVisiable(table, i, j);
			            	return true;
		            	}
						
						if (isCellEditable(table, i,modelJ)) {
							tmp = tmp.replaceAll(text, newText);
							tml.setValueAt(tmp, i, modelJ);
							makeCellVisiable(table, i, j);
							return true;
						}
					}
					break;
				case 10:
					// WHOLE_WORD
					if (tmp.equalsIgnoreCase(text)) {
						lastPoint.setLocation(i, j);
						if (newText == null) {
			            	makeCellVisiable(table, i, j);
			            	return true;
		            	}
						if (isCellEditable(table, i,modelJ)) {
							tmp = tmp.replaceAll(text, newText);
							tml.setValueAt(tmp, i, modelJ);
						}
						makeCellVisiable(table, i, j);
						return true;
					}
					break;
				case 11:
					// WHOLE_WORD & CASE_SENSITIVE
					if (tmp.equals(text)) {
						lastPoint.setLocation(i, j);
						if (newText == null) {
			            	makeCellVisiable(table, i, j);
			            	return true;
		            	}
						if (isCellEditable(table, i,modelJ)) {
							tmp = tmp.replaceAll(text, newText);
							tml.setValueAt(tmp, i, modelJ);
							makeCellVisiable(table, i, j);
							return true;
						}
					
					}
				}
				j++;
			}
			j=0;
		}
		// reset the last point
		lastPoint.setLocation(0, 0);
		return false;
	}
		
	/**
	 * Converts a visible column index to a column index in the model.
	 * Returns -1 if the index does not exist.
	 */
    public static int toModel(JTable table, int vColIndex) {
        if (vColIndex >= table.getColumnCount()) {
            return -1;
        }
        return table.getColumnModel().getColumn(vColIndex).getModelIndex();
    }
    
    /**
     * Converts a column index in the model to a visible column index.
     * Returns -1 if the index does not exist.
     */
    public int toView(JTable table, int mColIndex) {
        for (int c=0; c<table.getColumnCount(); c++) {
            TableColumn col = table.getColumnModel().getColumn(c);
            if (col.getModelIndex() == mColIndex) {
                return c;
            }
        }
        return -1;
    }	
}
